import { Button, DatePicker, TimePicker, Divider, Form, Input, Select, Radio, message, FormInstance, InputNumber, TreeSelect } from "antd";
import moment from 'moment';
import { useEffect, useState } from "react";
import RemoteSelect from "../../basic/RemoteSelect";
import CoordinateSelect from '../../basic/CoordinateSelect';
import RemoteTree from "../../basic/RemoteTree";
import FileUpload from "../../basic/FileUpload";
import ImageUpload from "../../basic/ImageUpload";
import styles from './index.module.sass';
import ImagePreview from "../../basic/ImagePreview";
import TreeTransfer from '../../basic/TreeTransfer';
import SimpleSwitch from "../../basic/SimpleSwitch";
import FencePanel from "../../basic/FencePanel";
import { InfoCircleOutlined } from '@ant-design/icons';

const { RangePicker: TimeRangePicker } = TimePicker;
const { RangePicker: DateRangePicker } = DatePicker;
const { TextArea } = Input;
const { TreeNode } = TreeSelect;


/**自定义输入控件类型 */
export enum InputType {
    Default = 1,
    SimpleSelect,
    RemoteSelect,
    /** CoordinateSelect: 联动选择器 */
    CoordinateSelect,
    SimpleDate,
    /**时间区域选择 */
    TimeRangePicker,
    /**日期区域选择 */
    DateRangePicker,
    /**日期时间区域选择 */
    DateTimeRangePicker,
    TextArea,
    SimpleRadio,
    SimpSwitch,
    Password,
    RemoteTree,
    /**文件上传 */
    FileUpload,
    /**图片上传 */
    ImageUpload,
    /**树形选择穿梭框 */
    TreeTransfer,
    /**数字输入框 */
    InputNumber,
    /**日期+时间的区域选择 */
    SimpleDateTime,
    /**树选择 */
    TreeSelect,
    /**用于切换配置项 */
    ItemRadio,
    /**电子围栏 */
    FenceMap
}

/**表单控件的使用类型为展示类型时，表单项的展示类型 */
export enum ShowType {
    /**只读状态的input */
    Default = 100,
    /**只读状态的TextArea */
    TextArea,
    /**单个图片预览展示 */
    Image,
    /**多个图片预览展示 */
    ImageList
}

/**表单控件的使用类型 */
export enum UseType {
    /**默认类型，即跳过限制 */
    Default = 150,
    /**新增类型 */
    Add,
    /**编辑类型 */
    Edit,
    /**展示类型 */
    Show,
    /**新增和编辑类型 */
    AE
}

interface FillFun {
    /**填充函数接口 */
    (form: FormInstance): any
}

/**输入控件的自定义选项，同时接管Form.Item的入参选项 */
interface Option {
    /**接管Form.Item的入参选项 */
    formItem?: any

    /**是否必填项 */
    isRequired?: boolean

    /**输入控件的自定义双列展示 */
    isDoubleRow?: boolean

    /**组件内部扩展项 */
    [index: string]: any

    /**配置提示信息的提示文字, 当配置了信息时显示提示图标 */
    tooltip?: string

    /**表单项动态显示的标志 */
    whenFields?: any,

    /**输入控件 是否禁用状态 */
    isDisabled?: boolean,
}

interface GlobalSet {
    /**是否双列展示输入项 */
    isDoubleRow?: boolean

    /**是否默认表单输入项都是必填项 */
    isDefaultRequired?: boolean,

    /**表单标签名称显示占比，默认为6（ant栅格） */
    labelColSpan?: number

    /**是否不使用默认的表单提交成功提示 */
    isNotSuccessAlt?: boolean

    /**是否不使用默认的表单提交失败提示 */
    isNotFailAlt?: boolean

    /**替换表单提交成功的提示文本 */
    successText?: string

    /**替换表单提交失败的提示文本 */
    failText?: string

    /**是否不显示表单操作按钮 */
    isNotShowFooterButton?: boolean

    /**是否重置后，恢复初始值 */
    isUseInitData?: boolean
}

export interface Props {
    /**
     * 表单项目得配置清单,label与key在数组中的位置不可变,其它项位置可变
     * 模式：[[label, key, InputType, UseType, ShowType, opt], ...]
     */
    inputs: any[][]

    /**表单使用的类型，不传以显示新增类型 */
    type?: UseType

    /**表单要装填的数据, 用于传入表单数据展示数据或者修改 */
    data?: any

    /**表单数据远程请求函数 */
    request?: Function

    /**表单请求额外的参数 */
    requestParams?: any

    /**经 Form.useForm() 创建的 form 控制实例 */
    formInstance?: any

    /**提供表单的数据填充功能 */
    onFill?: FillFun

    /**表单远程请求提交成功的回调 */
    onSuccess?: Function

    /**表单远程请求提交失败的回调 */
    onFail?: Function

    /**表单的全局设置 */
    global?: GlobalSet
}

const FormPanel: React.FC<Props> = ({
    inputs,
    type: formType = UseType.AE,
    data,
    request,
    requestParams,
    formInstance,
    onFill,
    onSuccess,
    onFail,
    global
}) => {
    const [form] = Form.useForm(formInstance);
    const [reset, setReset] = useState<number>(0);
    const [realInputs, setRealInputs] = useState<any[]>([]);
    const [formName] = useState<string>(() => Mock.Random.first())
    const [handleFill] = useState<any>(() => {
        if (NODE_ENV === 'development' && onFill) {
            return () => { onFill(form) };
        } else {
            return false;
        }
    })
    const [isLoading, setIsLoading] = useState<boolean>(false);

    /**
     * 监听表单控件配置入参，生成ant实际使用的表单配置
     */
    useEffect(() => {
        if (inputs.length !== 0) {
            const _inputs = [];
            for (let i = 0; i < inputs.length; i++) {
                const item = inputs[i];

                let label: string, key: string;
                let inputType: InputType = InputType.Default,
                    useType: UseType = UseType.Default,
                    showType: ShowType = ShowType.Default,
                    opt: Option = { formItem: {} };

                /**
                 * 解构入参配置
                 */
                [label, key] = item;
                for (let index = 2; index < item.length; index++) {
                    const target = item[index];
                    if (InputType[target]) { inputType = target }
                    else if (UseType[target]) { useType = target }
                    else if (ShowType[target]) { showType = target }
                    else if (_.isObject(target)) { opt = { ...opt, ...target } }
                }

                /**
                 * 解析全局配置，控件配置项覆盖全局配置项
                 */
                if (!_.isUndefined(opt.isRequired) ? opt.isRequired : global?.isDefaultRequired && _.isEmpty(opt.formItem.rules)) {
                    opt.formItem.rules = [{ required: true, message: `请输入${label}` }];
                }
                if (!_.isUndefined(opt.isDoubleRow) ? opt.isDoubleRow : global?.isDoubleRow) {
                    const labelSpan = global?.labelColSpan || 6;
                    const wrapperSpan = 24 - labelSpan;
                    opt.className = styles.item50;
                    opt.formItem.labelCol = { span: labelSpan };
                    opt.formItem.wrapperCol = { span: wrapperSpan };
                } else {
                    let labelSpan = 3;
                    if (global?.labelColSpan) {
                        const ret = _.divide(global?.labelColSpan, 2);
                        labelSpan = _.ceil(ret);
                    }
                    const wrapperSpan = 24 - labelSpan;
                    opt.className = styles.item100;
                    opt.formItem.labelCol = { span: labelSpan };
                    opt.formItem.wrapperCol = { span: wrapperSpan };
                }

                /**
                 * 解析简单配置提示信息配置项
                 */
                if (opt.tooltip && _.isUndefined(opt.formItem.tooltip)) {
                    opt.formItem.tooltip = {
                        title: opt.tooltip,
                        icon: <InfoCircleOutlined />
                    }
                }

                /**
                 * 基础ant的Switch组件联动，自动配置表单控件参数值名称
                 */
                if (inputType === InputType.SimpSwitch) {
                    opt.formItem.initialValue = true;
                }

                /**
                 * 完成配置项判断使用类型是否加入渲染数组
                 * useType：当前展示项的规则，代表当前项只会在对应的表单类型中显示
                 * formType：当前表单的使用类型，代表当前表单类型
                 */
                if ((useType === UseType.Default || (useType === UseType.AE
                    ? (formType === UseType.Add || formType === UseType.Edit)
                    : useType === formType))
                ) {
                    _inputs.push({ label, key, opt, inputType, useType, showType });
                    /**密码输入控件联动，额外自动生成密码确认输入项 */
                    if (inputType === InputType.Password) {
                        let confirmPasswordkey = `${key}Confirm`;
                        let confirmPasswordRules: any = [({ getFieldValue }: any) => ({
                            validator(_: any, value: any) {
                                if (getFieldValue(key) === value) {
                                    return Promise.resolve();
                                }
                                return Promise.reject(new Error(`确认${label}需要与输入的${label}一致`));
                            },
                        })]
                        if (_.find(opt.formItem.rules, { required: true })) {
                            confirmPasswordRules.push({ required: true });
                        }
                        const confirmPasswordInput = {
                            label: `确认${label}`,
                            key: confirmPasswordkey,
                            inputType: InputType.Password,
                            useType,
                            showType,
                            opt: _.cloneDeep(opt)
                        }
                        if (!confirmPasswordInput.opt?.formItem) {
                            confirmPasswordInput.opt.formItem = {};
                        }
                        confirmPasswordInput.opt.formItem.rules = confirmPasswordRules;
                        _inputs.push(confirmPasswordInput);
                    }

                }
            }

            /**
             * 解析表单项动态显示的标志
             */
            const allValues: any = {};
            _inputs.forEach((inp: any) => {
                allValues[inp.key] = inp.opt.formItem.initialValue
            });
            handleWhenFields(_inputs, allValues, false);

            setRealInputs(_inputs);
        }
    }, [inputs, global, formType, reset])

    /**
     * 监听表单数据入参，更新表单数据
     */
    useEffect(() => {
        if (data && form) {
            form.setFieldsValue(data);
        }
    }, [data, form])

    useEffect(() => () => { setIsLoading(false) }, []);

    async function handleFinish(values: any) {
        setIsLoading(true);
        try {
            if (request) {
                const _queryParams = {
                    ...requestParams,
                    ...values
                };
                await request(_queryParams);
                onSuccess && onSuccess(_queryParams);
                if (!global?.isNotSuccessAlt) {
                    message.success(global?.successText || '表单提交成功');
                }
                setIsLoading(false);
            }
        } catch (error: any) {
            console.error('FormPanel: 提交失败');
            onFail && onFail(error);
            if (!global?.isNotFailAlt) {
                message.error(global?.failText || error.msg);
            }
            setIsLoading(false);
        }
    }

    function handleReset() {
        if (data && global?.isUseInitData) {
            form.resetFields();
            form.setFieldsValue(data);
        } else {
            form.resetFields();
        }
        setReset((val) => ++val)
    }

    function handleClose() {
        onSuccess && onSuccess();
    }

    function handleValuesChange(changedValues: any, allValues: any) {
        handleWhenFields(realInputs, allValues, true);
    }

    function handleWhenFields(_realInputs: any[], allValues: any, isSet: boolean) {
        const whenFieldList = _realInputs.filter(inp => inp.opt.whenFields);
        if (whenFieldList.length !== 0) {
            const hiddenList = [];
            const showList = [];
            whenFieldList.forEach((inp: any) => {
                let is = true;
                const whenFields = inp.opt.whenFields;
                const keys = _.keys(whenFields);
                for (let i = 0; i < keys.length; i++) {
                    const key = keys[i];
                    // 如果是账号添加修改，选中管理员，隐藏权限区域；
                    if (allValues.hasOwnProperty("roleId")) {
                        if (whenFields[key] === allValues[key]) {
                            is = false;
                            break;
                        }
                    } else {
                        if (whenFields[key] !== allValues[key]) {
                            is = false;
                            break;
                        }
                    }

                }
                if (is && inp.opt.formItem.hidden === true) {
                    inp.opt.formItem.hidden = false;
                    inp.opt.formItem.rules = inp.opt.copyRules;
                    showList.push(inp);
                }
                if (!is && (inp.opt.formItem.hidden === false || _.isUndefined(inp.opt.formItem.hidden))) {
                    inp.opt.formItem.hidden = true;
                    inp.opt.copyRules = inp.opt.formItem.rules;
                    inp.opt.formItem.rules = undefined;
                    hiddenList.push(inp);
                }
            });
            if (isSet && (hiddenList.length !== 0 || showList.length !== 0)) {
                setRealInputs(_.clone(_realInputs));
            }
        }
    }

    return (
        <article>
            {realInputs.length > 0 && <Form
                className={styles.form}
                name={formName}
                form={form}
                onFinish={handleFinish}
                onValuesChange={handleValuesChange}
            >
                {realInputs.map(({ label, key, opt, inputType: type, showType }: any, idx: number) =>
                (key !== undefined ?
                    (<Form.Item
                        className={opt.className}
                        key={key}
                        label={label}
                        name={key}
                        {...opt.formItem}
                    >
                        {(!_.isUndefined(formType) && formType === UseType.Show)
                            ? (
                                (showType === ShowType.Image &&
                                    <ImagePreview />
                                ) ||
                                (showType === ShowType.TextArea &&
                                    <TextArea
                                        className={styles.textArea}
                                        rows={4}
                                        readOnly
                                    />) ||
                                (type === InputType.RemoteTree &&
                                    <RemoteTree
                                        remote={opt.remote}
                                        onCheck={opt.onCheck}
                                        defaultSelected={opt.defaultSelected}
                                        halfList={opt.halfList}
                                        isDisabled={true}
                                    />) ||
                                <Input readOnly />
                            )
                            : (
                                ((_.isUndefined(type) || type === InputType.Default) &&
                                    <Input
                                        placeholder={`输入${label}`}
                                        maxLength={opt.maxLength || 50}
                                        allowClear
                                        disabled={opt.isDisabled}
                                    />
                                ) ||
                                (type === InputType.SimpleSelect &&
                                    <Select
                                        style={{ width: opt.width }}
                                        placeholder={`选择${label}`}
                                        allowClear
                                        showSearch={opt.showSearch}
                                        mode={opt.mode}
                                        onSelect={opt.handleSelect}
                                        disabled={opt.disabled}
                                    >
                                        {opt.list.map((it: any) =>
                                            <Select.Option key={it.value} value={it.value}>{it.name}</Select.Option>
                                        )}
                                    </Select>) ||
                                (type === InputType.RemoteSelect &&
                                    <RemoteSelect
                                        placeholder={`选择${label}`}
                                        remote={opt.remote}
                                        template={opt.template}
                                        mode={opt.mode}
                                        onChange={opt.onChange}
                                    />) ||
                                (type === InputType.CoordinateSelect &&
                                    <CoordinateSelect
                                        remote={opt.remote}
                                        number={opt.number}
                                    />) ||
                                (type === InputType.SimpleDate &&
                                    <DatePicker
                                        className={styles.simpleDate}
                                        placeholder={`选择${label}查询`}
                                        allowClear
                                    />) ||
                                (type === InputType.TimeRangePicker &&
                                    <TimeRangePicker
                                        format={opt.format || 'HH:mm:ss'}
                                        disabled={opt.isDisabled}
                                        allowClear
                                        order={false}
                                        className={styles.timeRangePicker}
                                    />) ||
                                (type === InputType.DateRangePicker &&
                                    <DateRangePicker
                                        allowClear
                                        className={styles.dateRangePicker}
                                    />) ||
                                (type === InputType.DateTimeRangePicker &&
                                    <DateRangePicker
                                        allowClear
                                        format={`YYYY-MM-DD ${opt.dataFormat}`}
                                        showTime={{ format: opt.dataFormat }}
                                        className={styles.dateRangePicker}
                                    />) ||
                                (type === InputType.SimpleRadio &&
                                    <Radio.Group>
                                        {opt.list.map((it: any) =>
                                            <Radio key={it.value} value={it.value}>{it.name}</Radio>
                                        )}
                                    </Radio.Group>) ||
                                (type === InputType.SimpSwitch &&
                                    <SimpleSwitch {...opt}
                                    />) ||
                                (type === InputType.TextArea &&
                                    <TextArea
                                        className={styles.textArea}
                                        placeholder={`输入${label}`}
                                        allowClear
                                        maxLength={opt.maxLength || 250}
                                        showCount
                                        rows={4}
                                    />) ||
                                ((type === InputType.Password) &&
                                    <Input.Password
                                        allowClear
                                        placeholder={`请输入${label}`}
                                        autoComplete='off'
                                    />) ||
                                (type === InputType.RemoteTree &&
                                    <RemoteTree
                                        remote={opt.remote}
                                        onCheck={opt.onCheck}
                                        defaultSelected={opt.defaultSelected}
                                        halfList={opt.halfList}
                                    />) ||
                                (type === InputType.FileUpload && <FileUpload
                                    url={opt.url}
                                    uploadNumber={opt.uploadNumber}
                                    uploadFileType={opt.uploadFileType}
                                />) ||
                                (type === InputType.ImageUpload &&
                                    <ImageUpload
                                        url={opt.url}
                                        handleResponse={opt.handleResponse}
                                        number={opt.number}
                                    />) ||
                                (type === InputType.TreeTransfer &&
                                    <TreeTransfer
                                        treeData={opt.treeData}
                                    />) ||
                                (type === InputType.SimpleDateTime &&
                                    <DatePicker
                                        format="YYYY-MM-DD HH:mm:ss"
                                        showTime={{ defaultValue: moment('00:00:00', 'HH:mm:ss') }}
                                        className={styles.simpleDate}
                                        placeholder={`选择${label}查询`}
                                        disabled={opt.isDisabled}
                                        allowClear
                                    />) ||
                                (type === InputType.InputNumber &&
                                    <InputNumber
                                        style={{ minWidth: 160, maxWidth: 200 }}
                                        min={opt.min || '0'}
                                        max={opt.max}
                                        placeholder={`请选择...`}
                                        disabled={opt.isDisabled}
                                    />) ||
                                (type === InputType.TreeSelect &&
                                    <TreeSelect
                                        style={{ minWidth: 160, maxWidth: 200 }}
                                        showSearch
                                        dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
                                        placeholder="请选择..."
                                        allowClear
                                        treeDefaultExpandAll
                                    >
                                        {opt.list.map((it: any) =>
                                            <TreeNode disabled value={it.provinceCode} key={it.provinceCode} title={it.provinceName}>
                                                {it.baseCityRespDTOList.map((its: any) =>
                                                    <TreeNode disabled value={its.cityCode} key={its.cityCode} title={its.cityName}>
                                                        {its.baseAreaRespDTOList.map((itss: any) =>
                                                            <TreeNode value={itss.areaCode} key={itss.areaCode} title={itss.areaName}>
                                                            </TreeNode>
                                                        )}
                                                    </TreeNode>
                                                )}
                                            </TreeNode>
                                        )}
                                    </TreeSelect>
                                ) ||
                                (type === InputType.ItemRadio &&
                                    <Radio.Group>
                                        {opt.list.map((it: any) =>
                                            <Radio key={it.value} value={it.value}>{it.name}</Radio>
                                        )}
                                    </Radio.Group>) ||
                                (type === InputType.FenceMap &&
                                    <FencePanel />)
                            )
                        }
                    </Form.Item>)
                    : <Divider className={styles.divider} key={idx} orientation="left">{label}</Divider>)
                )}
                {(!global?.isNotShowFooterButton && formType === UseType.Show) ?
                    <footer className={styles.footer}>
                        <Button htmlType="button" onClick={handleClose}>
                            关闭
                        </Button>
                    </footer> :
                    <footer className={styles.footer}>
                        <Button type="primary" htmlType="submit" loading={isLoading} >
                            提交
                        </Button>
                        <Button htmlType="button" onClick={handleReset}>
                            重置
                        </Button>
                        {handleFill &&
                            <Button type="dashed" onClick={handleFill}>
                                填充
                            </Button>
                        }
                    </footer>
                }
            </Form>
            }
        </article>
    )
}

export default FormPanel;